#include <aclconio.h>
#include <errno.h>
#include <stdio.h>
#include <ascii.h>
#include <stdlib.h>
#include <acldev.h>
#include <string.h>
#include <aclstr.h>
#include <portdef.h>
#include <aclascii.h>
#include <applidl.h>
#include <ctype.h>
#include <actutil.h>
#include <svc.h>

//#include "C:\Verixaps\VMAC\include\logsys.h"
//#include "C:\VerixVaps\VMAC\ver150\include\logsys.h"
#include <logsys.h>

#include "PobTran.h"
#include "UserIf.h"
#include "pinpad.h"


VS_BOOL  gfPPadPresent = VS_TRUE;   /* Global flag to determine if PinPad is present */
PINPAD_OBJECT   obPinPad;
unsigned long   ulTimerCount;

int inColdInitPinpad(TRANSACTION_OBJECT *pobTran)
{
    int  inRetVal = VS_SUCCESS;
    DisplayStatus("Check PINPad...");

    /* Setup appropriate function pointers in global PinPad object */
    inSetupPinPad(inGetPINPadType());
    
    if (!gfPPadPresent)
        return VS_SUCCESS;

    inRetVal = inInitializePinPad();
    return inRetVal;
}

int inGetPinAccMac(TRANSACTION_OBJECT *pobTran, char *PINMsg)
{
    int inRetVal = 0;

    vdFlushKeyboardBuffer();
    if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
       DisplayStatus("PINPad Error!");
	   gfPPadPresent = VS_FALSE;
       return(VS_ERR);
    }
    inRetVal = obPinPad.inGetPin(pobTran, PINMsg);
    switch (inRetVal) {
        case PP_SUCCESS:        /* No error...continue */
            break;
        case PP_TIMEOUT:        /* An error occurred */
            DisplayStatus("PIN Entry Timeout!");
            return(VS_ERR);
        case PP_CANCEL:         /* An error occurred */
            DisplayStatus("Cancelled!");
			SVC_WAIT(1000);
            return(VS_ERR);
        case PP_CORRECT:        /* Correct pressed: code to loop */
            vdBeep();
            DisplayStatus("Correction...");
            return(PP_CORRECT);
        case PP_BADACCTLEN:     /* Account Number too short */
            DisplayStatus("Acc# Too Short!");
            return(VS_ERR);
        case PP_ERROR:          /* An error occurred */
        default:                /* Unknown error occurred */
            DisplayStatus("PINPad Error!");
			return(VS_ERR);
    }
    if (inResetPINPad() != VS_SUCCESS) {     /* Return PinPad to Idle */
		LOG_PRINTFF((0x08L, "Error Reset PINPad"));
        return(VS_ERR);
	}
    vdFlushKeyboardBuffer();
    return(VS_SUCCESS);
}

int inSetupPinPad(inPinPadType)
{
    gfPPadPresent = VS_TRUE;    /* Default value */

    switch (inPinPadType) {
        case NO_PINPAD:
            gfPPadPresent = VS_FALSE;
            break;
        case IPP:           /* Internal PinPad */
            inSetupIPPInfo(inPinPadType);
            break;        
        default:
            gfPPadPresent = VS_FALSE;   // Default is No Pinpad
            break;
    }
    return VS_SUCCESS;    
}

int inSetupIPPInfo(int inPinPadType)
{
    /* Set up PinPad object fields */
    obPinPad.inHandle               = -1;
    obPinPad.inType                 = inPinPadType;
    obPinPad.inTimeout              = PPADTIMEOUT;
    obPinPad.inInitPinPad           = inInitPinPad;
    obPinPad.inSetPinPadIdlePrompt  = inSetIPPIdlePrompt;
    obPinPad.inDisplayPinPadString  = inDispIPPStr;
    obPinPad.inGetPin               = inGetIPPPin;
    obPinPad.inGetTipAmount         = inGetIPPTipAmt;
    obPinPad.inPPadConnectTest      = inPPadConnectTest;
	obPinPad.vdSendAbortToPINPad    = vdSendAbortToPINPad;  //LIEM: forgoten?
    return VS_SUCCESS;    
}

int inInitializePinPad()
{
    int inRetVal;
    
    inRetVal = obPinPad.inInitPinPad();
    if (inRetVal != VS_SUCCESS) {
        gfPPadPresent = VS_FALSE;
        return VS_SUCCESS;  
    } else {
        gfPPadPresent = VS_TRUE;
    }
    inExecPinPadIdlePrompt();
    return (VS_SUCCESS);
}

int inExecPinPadIdlePrompt()
{
    int             inPPRetries = 5;
    unsigned long   ulPPTimeOut;

    ulPPTimeOut = set_itimeout(NO_CLOCK_HANDLE obPinPad.inTimeout, TM_SECONDS);
    while (CHECK_TIMEOUT(ulPPTimeOut)) {
        if (obPinPad.inSetPinPadIdlePrompt() == VS_SUCCESS) {
            gfPPadPresent = VS_TRUE;
            break;
        }
        if (!(--inPPRetries) || !(CHECK_TIMEOUT(ulPPTimeOut))) {
            DisplayStatus("PINPad Error...");
		    gfPPadPresent = VS_FALSE;
            break;
        }
        vdDelay(1000);  /* Wait for 1 second and try again */
    }
    return VS_SUCCESS;
}

int inInitPinPad()
{
    int             inPinPadType;
    struct Opn_Blk  srPinPadInit;    /* Structure used for PinPad param init */

    memset((char *)&srPinPadInit, 0x00, sizeof(srPinPadInit));
    srPinPadInit.rate      = (char)inGetPinBarBaudRate();   /* Info found in TCT */
    srPinPadInit.format    = (char)inGetPinBarDataFormat(); /* Info found in TCT */
    srPinPadInit.protocol  = P_char_mode;
    srPinPadInit.parameter = 0;
    
    if (obPinPad.inHandle != -1) {
        if (close(obPinPad.inHandle) != 0) {
            DisplayStatus("PINPad Error!");
            return(VS_ERR);
        }
	}
#ifdef __arm
	obPinPad.inHandle = open("/dev/com5", O_RDWR);
#else
    obPinPad.inHandle = open("/dev/com2", O_RDWR);
#endif
    if (obPinPad.inHandle < 0) {
        DisplayStatus("PINPad Error!");
        return(VS_ERR);
    }    
    if (set_opn_blk(obPinPad.inHandle, &srPinPadInit)) {
        DisplayStatus("PINPad Error!");
        return(VS_ERR);         /* Error in setting the port's parameters */
    } else {
        if (inGetPINPadType() == IPP) {
            select_pinpad(PINPAD_INTERNAL);
            SVC_WAIT(50);
            IPP_power(PINPAD_ON);
            SVC_WAIT(300);  // Need this here per the Verix Func spec.
        } else {
            select_pinpad(PINPAD_EXTERNAL);
            SVC_WAIT(50);
            IPP_power(PINPAD_OFF);
            SVC_WAIT(300);  // Need this here per the Verix Func spec.
        }
        if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
            close(obPinPad.inHandle);
            DisplayStatus("PINPad not Connected!");
            gfPPadPresent = VS_FALSE;
            return(VS_ERR);
        }

        inPinPadType = inGetPINPadType();
        if ((inPinPadType == PP1000) || (inPinPadType == PP2000)) {            
            if (inSetKeyManagement() != PP_CORRECT) {
                DisplayStatus("PINPad Error!");
                return(VS_ERR);
            }
        }
        return(VS_SUCCESS);     /* Success in setting the port's parameters */
    }
}

int inSendPinPadData(char *pchMsg, int inTimeout, VS_BOOL fWaitForAck)
{
    int     inNumRetry = 0;
    int     inRetval;
    VS_BOOL bAddFraming = TRUE;
    
    if (!gfPPadPresent)
        return(VS_ERR);

    if (pchMsg[0] != SI)
        bAddFraming = TRUE;
    else
        bAddFraming = FALSE;

    inRetval = inSendComPacket(obPinPad.inHandle, pchMsg, strlen(pchMsg), 
                       bAddFraming, inTimeout, fWaitForAck, PP_MAX_RETRIES);

    if (inRetval < 0) {
        DisplayStatus("PINPad Error!");
		SVC_WAIT(2000);
        return(VS_ERR);
    }
    return (VS_SUCCESS);
}

int inRecvPinPadData(char *pchRecvBuf, int inTimeout, int inMaxRecSize, VS_BOOL fSendAck)
{
    int     inRetval;

    inRetval = inRecvCModePacket(obPinPad.inHandle, pchRecvBuf, inMaxRecSize, FALSE, 
                      inTimeout, fSendAck, PP_MAX_RETRIES);

    if (inRetval == ERR_COM_TIMEOUT) {
        DisplayStatus("PINPad Error!");
		return (VS_TIMEOUT);
    } else if (inRetval == VS_ESCAPE) {
        inResetPINPad();
        return (VS_ESCAPE);
    } else if (inRetval > 0) {
        if (!memcmp(&(pchRecvBuf[1]), "Z51?", 4)){
            DisplayStatus("PINPad Error!");
			return (VS_TIMEOUT);
        }
        return inRetval;    /* Return # of bytes received */
    }
    return (VS_ERR);
}

int inSetIPPIdlePrompt()
{
    return VS_SUCCESS;  /* No PinPad idle prompt for IPP! */
}


int inResetPINPad()
{
    char pchPinPadBuf[PINPAD_BUFFER_SIZE];

    if (inGetPINPadType() == IPP)
        vdFlushKeyboardBuffer();

    strcpy(pchPinPadBuf, "72");
    
    if (inSendPinPadData(pchPinPadBuf, 2, VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}

int inDispIPPStr(char chClrDisplay, char *pszDispStr)
{
    if (chClrDisplay == CLR)
        clrscr();
    DisplayStatus(pszDispStr);
    return(VS_SUCCESS);
}


int inPPadConnectTest(void)
{
    char pchPINBuf[PINPAD_BUFFER_SIZE];

    memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
    if (inGetPINPadType() == IPP)
        vdFlushKeyboardBuffer();

    pchPINBuf[0] = SI;
    strcat(pchPINBuf, "11");
    pchPINBuf[strlen(pchPINBuf)] = SO;

    if (inSendPinPadData(pchPINBuf, PPADTIMEOUT/2, VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}

static int inGetIPPPin(TRANSACTION_OBJECT *pobTran, char *MsgPIN)
{
    char szPAN[PAN_SIZE + 1], szPINBlock[PIN_SIZE + 1];
    char szMaxPIN[2 + 1], szMinPIN[2 + 1];
    char pchPINBuf[PINPAD_BUFFER_SIZE];
    char szKSN[KSN_SIZE+1];
    int  inSize, inCnt=0;                      /* No of retries set to 0 */
    char pszEncKey[PIN_SIZE + 1];
	char buff[128];

    memset(szKSN, '\0', sizeof(szKSN));
    if (inGetEncryptMethod() != DUKPT)
        if (inSelectMasterKey() != VS_SUCCESS)
            return(PP_ERROR);

 	//pszEncKey = szGetPINKey();  //LIEM
	memset(buff, 0x00, sizeof(buff));
	memset(pszEncKey, 0x00, sizeof(pszEncKey));
	inGetPINKey(buff);
	strncpy(pszEncKey, buff, 16);

    //strcpy(szPAN, pobTran->srBRec.szPAN);
	strcpy(szPAN, pobTran->szPAN);  //LIEM
    sprintf(szMinPIN, "%02d", inGetMinPINDigit());
    sprintf(szMaxPIN, "%02d", inGetMaxPINDigit()); //LIEM

    memset(pchPINBuf, 0, sizeof(pchPINBuf));
    strcpy(pchPINBuf, "Z63.");              /* Start of packet */
    strcat(pchPINBuf, szPAN);               /* Card Account Number */
    pchPINBuf[strlen(pchPINBuf)] = FS;      /* To separate the Account Number */
    if (inGetEncryptMethod() != DUKPT)
       strcat(pchPINBuf, pszEncKey);         /* Append Working Key for Master-Session */
    else
       strcat(pchPINBuf, "DUKPT ENCRYPTION");
    strcat(pchPINBuf, szMinPIN);            /* Minimum PIN length */
    strcat(pchPINBuf, szMaxPIN);            /* Maximum PIN length */
    pchPINBuf[strlen(pchPINBuf)] = 'N';     /* Null PIN allowed flag; 'N' = No null PIN */
    pchPINBuf[strlen(pchPINBuf)] = '*';     /* Echo char */
    
    vdFlushKeyboardBuffer();
    vdWarnBeep();
	write_at(MsgPIN, strlen(MsgPIN), 1, 7);
	if (strlen(MsgPIN)>=15) vdScrollDisplay();
    gotoxy(15, 7);  // Set up so PIN entry will start here, 16 not work well for OS 4A4 and 6A2
	set_font("");  // This is needed for the backspace to work, by using the default font.
	
    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS){
		LOG_PRINTFF((0x08L, "Error inSendPinPadData"));
        return(PP_ERROR);       /* Exit if inSendPinPadData fails */
	}        
    inSize = inRecvPinPadData(pchPINBuf, inGetPPTimeOut(), sizeof(pchPINBuf), VS_TRUE);
    if (inSize == VS_ESCAPE) {   /* Aborting from terminal, via Clear key */
		LOG_PRINTFF((0x08L, "PIN Entry Cancel"));
        return(PP_CANCEL);
	}
    if ((inSize == 0) || (inSize == VS_TIMEOUT)) {
		LOG_PRINTFF((0x08L, "PINPad Timeout Error, size = 0"));
        if (inResetPINPad() != VS_SUCCESS)
            return(PP_ERROR);
        return(PP_TIMEOUT);             /* Nothing Received */
    }
    if (inGetEncryptMethod() != DUKPT)
        if ((inSize != PINPAD_PIN_RESP_LEN) && (pchPINBuf[0] != EOT)) {
            if (!memcmp(&(pchPINBuf[1]), "71", 2)) {
                vdDispPinPadPkt73Error(pchPINBuf[3]);
				SVC_WAIT(1000);
				LOG_PRINTFF((0x08L, "An Error Occured"));
            }
			LOG_PRINTFF((0x08L, "PINPad Timeout Error"));
            return(PP_TIMEOUT);
        }
		if (pchPINBuf[0] == EOT) {           /* CANCEL to act as Correction Key */
			LOG_PRINTFF((0x08L, "PIN Entry Cancel as corecction"));
			return(PP_CANCEL);
		}
    if (inGetEncryptMethod() != DUKPT){
        strlcpy(szPINBlock, &(pchPINBuf[9]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */
    } else {
        if ((!memcmp(&(pchPINBuf[1]), "73", 2)) && inSize == 6) {
            vdDispPinPadPkt73Error(pchPINBuf[3]);
        }            
        /* The expected packet is <STX>710[KSN 16-20][PIN Block 16]<ETX> */
        while (pchPINBuf[inCnt] != ETX && inCnt < (int)strlen(pchPINBuf))
            inCnt++;
        strlcpy(szPINBlock, &(pchPINBuf[inCnt-PIN_BLOCK_SIZE]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */
        strlcpy(szKSN, &(pchPINBuf[9]), inCnt-9-PIN_BLOCK_SIZE);
        pad(szKSN, szKSN, 'F', KSN_SIZE - 9, RIGHT);
        strlcpy(pobTran->szKSN, szKSN, KSN_SIZE);
    }
    if (szPINBlock[0] == '\0') {
		LOG_PRINTFF((0x08L, "PINPad Buffer Empty Error"));
        return (PP_CANCEL);
	}
    strlcpy(pobTran->szPIN, szPINBlock, PIN_SIZE);  /* Set in the Transaction Object */
	LOG_PRINTFF((0x08L, "%s", szPINBlock));
	LOG_PRINTFF((0x08L, "%s", szKSN));
    LOG_PRINTFF((0x08L, "PIN Entry Success"));
    return(PP_SUCCESS);    
} /* end func inGetIPPPin() */


void vdDispPinPadPkt73Error(char chError)
{
    switch (chError) {
        case '1':   /* No key */
            DisplayStatus("No Master Key!");
            break;
        case '2':   /* Account error */
            DisplayStatus("Account Error!");
            break;
        case '3':   /* PIN too long */
            DisplayStatus("PIN Too Long!");
            break;
        case '4':   /* PIN too short / non-decimal PIN digit in PIN */
            DisplayStatus("PIN Too Short!");
            break;
        case '6':   /* PIN Pad has over 1 million transactions */
            DisplayStatus("Has Over 1 Million!");
            break;
        default:    /* Invalid error */
            return;
    }
    return;
}

int inGetIPPTipAmt(TRANSACTION_OBJECT *pobTran)
{
	//LIEM : not used
    return VS_SUCCESS;
}


void vdSendAbortToPINPad()
{
	char szBuffer[PINPAD_BUF_SIZE + 1];
	if (inGetPINPadType() == IPP) {return;} //LIEM : unknown error
	if ( gfPPadPresent ) {
    	if ( obPinPad.inPPadConnectTest() == VS_SUCCESS ) {
			strcpy(szBuffer, "72");
	    	inSendPinPadData (szBuffer, inGetPPTimeOut(), VS_TRUE);
		} else {
    	   gfPPadPresent = VS_FALSE;
    	}
    }
}

int inSelectMasterKey()
{
    char pchPINBuf[PINPAD_BUFFER_SIZE];

    memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
    pchPINBuf[0] = SI;
    strcat(pchPINBuf, "08");
    pchPINBuf[strlen(pchPINBuf)] = chGetMasterKeyAddress();
    pchPINBuf[strlen(pchPINBuf)] = SO;

    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}

int inTransferMasterKey(char MKAddress, char *szMasterKey)
{
    int inRetVal = 0;
	int inSize = 0;
	char pchPINBuf[PINPAD_BUFFER_SIZE];

	LOG_PRINTFF((0x08L, "--inTransferMasterKey--"));
    vdFlushKeyboardBuffer();
    if (obPinPad.inPPadConnectTest() != VS_SUCCESS) {
       DisplayStatus("PINPad Error!");
	   gfPPadPresent = VS_FALSE;
       return(VS_ERR);
    }

    memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
    pchPINBuf[0] = SI;
    strcat(pchPINBuf, "02");
    //pchPINBuf[strlen(pchPINBuf)] = chGetMasterKeyAddress();
	pchPINBuf[strlen(pchPINBuf)] = MKAddress;
	strcat(pchPINBuf, szMasterKey);
    pchPINBuf[strlen(pchPINBuf)] = SO;

    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) == VS_SUCCESS) {
		memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
		inSize = inRecvPinPadData(pchPINBuf, inGetPPTimeOut(), sizeof(pchPINBuf), VS_TRUE);
		if (inSize == VS_ESCAPE) {   /* Aborting from terminal, via Clear key */
			LOG_PRINTFF((0x08L, "Transfer Master Key Canceled"));
		} else if ((inSize == 0) || (inSize == VS_TIMEOUT)) { /* Nothing Received */
			LOG_PRINTFF((0x08L, "PINPad Timeout Error, size = 0"));
		} else {
			LOG_PRINTFF((0x08L, "PP Resp: (%d)[%s]", strlen(pchPINBuf), pchPINBuf));
			LOG_PRINT_HEX((unsigned char *)pchPINBuf, strlen(pchPINBuf));
			strcpy(pchPINBuf, &pchPINBuf[4]);
			pchPINBuf[16]=0x00;
			if (strcmp(pchPINBuf, szMasterKey)) {
				LOG_PRINTFF((0x08L, "Error Master Key Echo"));
				inSize = 0;
			}
			inRecvCModePacket(obPinPad.inHandle, pchPINBuf, sizeof(pchPINBuf), FALSE, inGetPPTimeOut(), FALSE, PP_MAX_RETRIES);
		}
	}
	
    if (inResetPINPad() != VS_SUCCESS) {     /* Return PinPad to Idle */
		LOG_PRINTFF((0x08L, "Error Reset PINPad"));
        return(VS_ERR);
	}
    vdFlushKeyboardBuffer();
	LOG_PRINTFF((0x08L, "--inTransferMasterKey--End--"));
	if (inSize<=0) return (VS_ERR);
	return(VS_SUCCESS);
}


int PINPAD_CODE_CHECK(char * a,char *b,int *  c,char * d,unsigned char * e)
{
	GET_VER(a,b,c,d,e);
	return 1;
}


void vdUpperCasePinMsg(char *pchString)
{
    int  inLen, inCount;
    inLen = strlen(pchString);
    for( inCount=0; inCount < inLen; inCount++ ) {
        if (isalpha(pchString[inCount]))
            pchString[inCount]=toupper(pchString[inCount]);	  	
    }
    
} /* end func vdUpperCasePinMsg() */

int inSetKeyManagement()
{
    char szPINBuf[PINPAD_BUFFER_SIZE];
    int  inRetCode;

    memset(szPINBuf, 0x00, sizeof(szPINBuf));
    szPINBuf[0] = SI;

    if (inGetEncryptMethod() == DUKPT) {
        strcat(szPINBuf, "15DKEY");
    } else {
        strcat(szPINBuf, "15MKEY");
    }
    szPINBuf[strlen(szPINBuf)] = SO;
    if (inSendPinPadData(szPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(PP_ERROR);               /* End if SendPinPadData fails */
    inRetCode = inRecvPinPadData(szPINBuf, inGetPPTimeOut(),sizeof(szPINBuf),VS_TRUE);
    if (inRetCode == VS_ESCAPE)         /* Aborting from terminal, via Clear key */
        return(PP_CANCEL);
    if ((inRetCode == 0) || (inRetCode == VS_TIMEOUT))
        return(PP_TIMEOUT);             /* Nothing Received */
    return(PP_CORRECT);
}

int inSendComPacket(int inHandle, char *pchMsg, int inMsgSize, VS_BOOL fPadStxEtx, 
                    int inACKTimeOut, VS_BOOL fWaitForAck, int inMaxRetries)
{
    char chResp;
    int  inSize = 0;
    int  inNumRetry = 0;
    char szSendBuf[SEND_BUF_SIZE + 1];

    if (inHandle < 0) 
        return(VS_ERR);
    memset(szSendBuf, 0, (int)sizeof(szSendBuf));
    
    if (fPadStxEtx == VS_TRUE) {
        szSendBuf[inSize] = STX; 
        inSize++;
        memcpy(&(szSendBuf[1]), pchMsg, inMsgSize); 
        inSize += inMsgSize;
        szSendBuf[inSize] = ETX; 
        inSize++;
    } else {
        memcpy(szSendBuf, pchMsg, inMsgSize); 
        inSize = inMsgSize;
    }
    szSendBuf[inSize] = (char) SVC_CRC_CALC(0, &(szSendBuf[1]), (inSize - 1));
    inSize++;
    
    do {                                   /* Clear any prev responses */
        while (read(inHandle, &chResp, 1) > 0) ;
        inNumRetry++;
                                                             /* transmit the packet */
        if (write(inHandle, (char *) szSendBuf, inSize) != inSize) 
            return(ERR_COM_SEND); 
        ulTimerCount = set_itimeout(NO_CLOCK_HANDLE inACKTimeOut, TM_SECONDS);
    
        if (fWaitForAck == VS_TRUE) {
            chResp = NAK;              /* Wait for reply till Timeout */
            while ((read(inHandle, &chResp, 1) == 0) && (CHECK_TIMEOUT(ulTimerCount)));
        } else
            chResp = ACK;
    } while ((chResp != ACK) && (inNumRetry < inMaxRetries));
    
    if (chResp == ACK) 
        return (VS_SUCCESS);
    else
        return (ERR_COM_NAK);  /* Too many NAKs, so indicate to the app */
}


int inRecvCModePacket(int inHandle, char *pchRecBuf, int inMaxRecSize, VS_BOOL fStripStxEtx, 
                      int inRespTimeOut, VS_BOOL fSendAck, int inMaxRetries)
{
    VS_BOOL fLRC;
    VS_BOOL fEnd = VS_FALSE;
    VS_BOOL fTimedOut = VS_FALSE;
#ifdef __arm
    char    chCheckSO = (char)-1;  /* Default = uninitialized */
#else 
	char    chCheckSO = -1;  /* Default = uninitialized */
#endif
    char    chAckOrNak;
    char    szRecBuf[RECV_BUF_SIZE + 1];
    int     inLRC;
    int     inNumRetry = 0;
    int     inSize;

	LOG_PRINTFF((0x08L, "inRecvCModePacket()"));
	//vdFlushKeyboardBuffer();
    do {
        inSize = 0;
        fEnd = VS_FALSE;
        memset(szRecBuf, 0x00, (int)sizeof(szRecBuf));
        inNumRetry++;

        if (inRespTimeOut)    /* If a timeout was passed */
            ulTimerCount = set_itimeout(NO_CLOCK_HANDLE inRespTimeOut, TM_SECONDS);
		
		//LOG_PRINTFF((0x08L, "OUTSIDE inSize = [%d] inNumRetry = [%d] szRecBuf(0)=[%d]", inSize, inNumRetry, (int)szRecBuf[0]));
        while(1) {
            if (inRespTimeOut) {
                if (CHECK_TIMEOUT(ulTimerCount) == 0) {
                    fTimedOut = VS_TRUE;
                    break;  /* Timeout occurred */
                }
            }
            if (read(inHandle, szRecBuf+inSize, 1) > 0) {
                inSize++;
                if (inSize >= sizeof(szRecBuf)) {
                    return VS_ERROR;
                }
#ifdef __arm
                if (chCheckSO == (char)-1) {
#else
				if (chCheckSO == -1) {
#endif
                    if (szRecBuf[0] == STX) 
                        chCheckSO = VS_FALSE;
                    else
                        chCheckSO = VS_TRUE;
                }
                if (fEnd == VS_TRUE) {
					LOG_PRINTFF((0x08L, "SUCCESS : inSize-2 == ETX or SO"));
					LOG_PRINT_HEX((unsigned char *)szRecBuf, inSize-1);
                    break;
				}
                if ((szRecBuf[ inSize - 1 ] == ETX) && (chCheckSO == VS_FALSE)) {
                    fEnd = VS_TRUE; /* Break out only after reading LRC */
                }else if ((szRecBuf[ inSize - 1 ] == SO) && (chCheckSO == VS_TRUE)) {
                    fEnd = VS_TRUE;
                }else if (szRecBuf[ inSize - 1 ] == EOT) {
					LOG_PRINTFF((0x08L, "ERROR : inSize-1 == EOT"));
					LOG_PRINT_HEX((unsigned char *)szRecBuf, inSize);
					return(VS_ESCAPE);
				}
            }
            if (gu_clr_state())     /* CANCEL key pressed */
                return(VS_ESCAPE);
        } 
        if (inSize == 0 || inSize == 1) {
            fTimedOut=VS_TRUE;
            break;                  /* No response from device - timed out */
        }
        if (szRecBuf[0] == EOT) 
            break;                  /* EOT received....break! */
        inLRC = SVC_CRC_CALC(0, &(szRecBuf[1]), inSize - 2);
        fLRC = (char) (szRecBuf[inSize-1] == inLRC);
        if (szRecBuf[inSize-1] == 0x00)    /* If LRC == NULL_CH, change so string */
            szRecBuf[inSize-1] = 0x01;     /* ops will function correctly later */
        szRecBuf[inSize] = 0x00;           /* NULL_CH the packet */
        /* Send ACK or NAK depending on device Response */
        if (fSendAck) {
            chAckOrNak = (char) (fLRC ? ACK : NAK);
            write(inHandle, &chAckOrNak, 1);
        }
    } while((!fLRC) && (inNumRetry < inMaxRetries));
    if (fTimedOut) {
		LOG_PRINTFF((0x08L, "ERROR : TIMEOUT"));
        return (ERR_COM_TIMEOUT);
    }
    /* Strip off STX/ETX if required */
    if (fStripStxEtx) {
        memcpy ((char *) szRecBuf, (char *) szRecBuf+1, (inSize - 3));
        szRecBuf[inSize - 3] = 0;
        inSize -= 3;
    }
    strncpy(pchRecBuf, szRecBuf, inMaxRecSize);                 
    inSize = (inSize < inMaxRecSize) ? inSize : inMaxRecSize;
	LOG_PRINTFF((0x08L, "inRecvCModePacket()...OK"));
    return(inSize);
}

//LIEM : Redefinition Function
int inGetPINPadType(void)
{
	return IPP;
}

char chGetMasterKeyAddress(void)
{
	char buff[128];
	memset(buff, 0x00, sizeof(buff));
	get_env_x(HOST_PINPAD, 0, buff);
	return buff[0];
}

int inGetPINKey(char *buff)
{
    get_env_x(HOST_PINKEY, 0, buff);
	return 1;
}

int inGetEncryptMethod(void)
{
	char buff[128];
	memset(buff, 0x00, sizeof(buff));
	get_env_x(HOST_PINPAD, 1, buff);
	return atoi(buff);
}

int inGetMinPINDigit(void)
{
	char buff[128];
	memset(buff, 0x00, sizeof(buff));
	get_env_x(HOST_PINKEY, 1, buff);
	return atoi(buff);
}

int inGetMaxPINDigit(void)
{
	char buff[128];
	memset(buff, 0x00, sizeof(buff));
	get_env_x(HOST_PINKEY, 2, buff);
	return atoi(buff);
}

int inGetPPTimeOut(void)
{
	char buff[128];
	memset(buff, 0x00, sizeof(buff));
	get_env_x(HOST_PINPAD, 2, buff);
	return atoi(buff);
}

int inGetPinBarBaudRate(void)
{
	char buff[128];
	memset(buff, 0x00, sizeof(buff));
	get_env_x(HOST_PINPAD, 3, buff);
	return atoi(buff);
}

int inGetPinBarDataFormat(void)
{
	char buff[128];
	memset(buff, 0x00, sizeof(buff));
	get_env_x(HOST_PINPAD, 4, buff);
	return atoi(buff);
}

///PINPAD PC//////////////////////////////////////////////
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
#define		EOT				0x04/*End of Transmission*/
#define		ENQ				0x05/*Enquiry*/
#define		ACK				0x06/*Acknowledgement*/
#define		SUCCESS			0x00/*Success*/
#define		WRONGPIN		0x01/*Wrong PIN*/
#define 	WRONGPAN		0x02/*Wrong PAN*/
#define		PINTO			0x03/*PIN Comm Error----time out PIN verification*/
#define		WK				0x0A/*Working Key*/
#define		WKACK			0x0B/*Working key Acknowledgement*/
#define		CANCELKEY		0x0C/*Cancel Key pressed*/
#define		UnAuthCard		0x0D/*Unauthorised Card*/
#define		TOSWIPE			0x10/* Time out for Card Swipe*/
#define		TOPIN			0x11/*Time out in PIN entre*/
#define     TOCOMM			0x12/*Timeout waiting host/bds response*/ //add by liem

#define		KILL			0xFF
#define		KILLACK			0xF0
#define		BIN				0xEE
#define		BINACK			0xE0

#define		PINREQ			0x07/*Request for PIN*/
#define		PINSEND			0x08/*Send PIN*/
#define		PINRES			0x09/*Result of PIN verfication*/
#define		PINACK			0x0E/*PIN Acknowledgement*/

#define		PINCREATEREQ	0x12/*Request for pin create by FES*/
#define		PINCREATERES	0x13/*Result of PIN create*/

#define		PINCHANGEREQ	0x14/*Request for pin change by FES*/
#define		PINCHANGESEND   0x15/*Send track2, old PIN, new PIN*/
#define		PINCHANGERES	0x16/*Result of PIN change*/

#define		CARDCAPREQ		0x30/*Request for card capture*/
#define		CARDCAPSEND		0x31/*Send card no*/

#define		TINCHANGEREQ	0x40/*Request for tin change by FES*/
#define		TINCHANGESEND	0x41/*Send track2, PIN, TIN*/
#define		TINCHANGERES	0x42/*Result of TIN change*/

#define		TINREQ			0x50/*Request for TIN*/

int hComPort = 0;
char szWorkingKey[20];
char chCommandSession;

int inEnableFrontEndPinpad(void)
{
   char buff[128];
   memset(buff, 0x00, sizeof(buff));
   get_env_x("FE-PINPAD", 0, buff);
   vdTrimSpace(buff);
   if (buff[0]=='1') return 1;
   return 0;
}


int inDoPinpadRecvProcessSend(void) 
{
	int inRetval = 1;
	int inRespBuff = 0;
	int inReqBuff = 0;
	char szReqBuff[MSG_BUFF_SIZE + 1];
	char szRespBuff[MSG_BUFF_SIZE + 1];
	char buff[128];

	memset(szReqBuff, 0x00, sizeof(szReqBuff));
	memset(szRespBuff, 0x00, sizeof(szRespBuff));
	memset(buff, 0x00, sizeof(buff));
	inReqBuff = inReadComPort(szReqBuff, 15);
	chCommandSession = szReqBuff[0];

	if (inReqBuff <= 0) {						//unsuccessful read com
		inRetval = 0;
		return 0;
	} else if (szReqBuff[0] == ENQ) {			//isOnline 
		szRespBuff[0] = ACK;
		SVC_INFO_SERLNO(&szRespBuff[1]);
		inRespBuff = 12;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		DisplayStatus("PINPAD ONLINE");
		SVC_WAIT(0);
		return 1;
	} else if (szReqBuff[0] == WK) {			//wk download
		szRespBuff[0] = WKACK;
		inRespBuff = 1;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		DisplayStatus("WK DOWNLOADED");
		memset(szWorkingKey, 0x00, sizeof(szWorkingKey));
		SVC_HEX_2_DSP(&szReqBuff[1], szWorkingKey, 8);
		SVC_WAIT(0);
		return 1;
	} else if (szReqBuff[0] == PINCREATEREQ) {
		char szEncNewPin1[20];
		char szEncNewPin2[20];
		char szCardPan[20];
		char szT2Data[TRACK2_SIZE +1];
		int i=0;
		memset(szT2Data, 0x00, sizeof(szT2Data));
		memset(szCardPan, 0x00, sizeof(szCardPan));
		clrscrplus("CREATE PIN");

		inRetval = inGetCardForPinpad(szT2Data, szCardPan);
		if (inRetval == 0) {	//card swipe not success
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = UnAuthCard; //UnAuthCard
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff);
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -1) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY;  //CANCELKEY
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -2) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOSWIPE;  //timeout
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}
		
		for (i=0; i<2; i++) {
			vdScrollDisplay();
			if (i==0){
				memset(szEncNewPin1, 0x00, sizeof(szEncNewPin1));
				inRetval = inGetPinForPinpad(szEncNewPin1, "ENTER NEW PIN");
			} else {
				memset(szEncNewPin2, 0x00, sizeof(szEncNewPin2));
				inRetval = inGetPinForPinpad(szEncNewPin2, "RE-ENTER NEW PIN");
			}
			if (inRetval == PP_TIMEOUT) {
				szRespBuff[0] = PINSEND;
				szRespBuff[1] = TOPIN; // ==>timeout
				inRespBuff = 2;
				inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
				vdDisplayPinpadStatus(szRespBuff); 
				SVC_WAIT(5000);
				return 0;
			} else if (inRetval != PP_SUCCESS) {
				szRespBuff[0] = PINSEND;
				szRespBuff[1] = CANCELKEY; //Cancelled
				inRespBuff = 2;
				inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
				vdDisplayPinpadStatus(szRespBuff); 
				SVC_WAIT(5000);
				return 0;
			}
		}
		if (memcmp(szEncNewPin1, szEncNewPin2, 8)) {
			szRespBuff[0] = PINACK;
			inRespBuff = 1;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
			szRespBuff[0] = PINCREATEREQ;
			szRespBuff[1] = CANCELKEY; //PIN tidak sama
			vdDisplayPinpadStatus(szRespBuff);	
			SVC_WAIT(3000);
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY; //Cancelled
			vdDisplayPinpadStatus(szRespBuff);	
			SVC_WAIT(3000);
			return 0;
		}
		// Send 08h + Track2 Data + 8-byte encrypted NEW PIN block 
		vdScrollDisplay();
		DisplayStatus("PLEASE WAIT...");
		memset(buff, 0x00, sizeof(buff));
		SVC_DSP_2_HEX(szEncNewPin1, buff, 8);
		szRespBuff[0] = PINSEND;
		szRespBuff[1] = 0x3B;
		strcpy(&szRespBuff[2], szT2Data);
		memcpy(&szRespBuff[2+strlen(szT2Data)], buff, 8);
		inRespBuff = 2+strlen(szT2Data)+8;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		memset(szReqBuff, 0x00, sizeof(szReqBuff));
		memset(szRespBuff, 0x00, sizeof(szRespBuff));
		inReqBuff = inReadComPort(szReqBuff, 30);
		DisplayStatus(" ");
		if (inReqBuff<=0 || szReqBuff[0] != PINCREATERES) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOCOMM; // ==>timeout
			inRespBuff = 2;
			vdDisplayPinpadStatus(szRespBuff); 
			DisplayStatus("SYSTEM ERROR");		//or timeout/com error
			SVC_WAIT(5000);
			return 0;
		}
		szRespBuff[0] = PINACK;
		inRespBuff = 1;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
		vdDisplayPinpadStatus(szReqBuff);	//display sesuai response
		SVC_WAIT(5000);
		return 1;						
	} else if (szReqBuff[0] == PINCHANGEREQ) {
		char szEncPin[20];
		char szEncNewPin1[20];
		char szEncNewPin2[20];
		char szCardPan[20];
		char szT2Data[TRACK2_SIZE +1];
		int i=0;
		memset(szT2Data, 0x00, sizeof(szT2Data));
		memset(szCardPan, 0x00, sizeof(szCardPan));
		clrscrplus("CHANGE PIN");

		inRetval = inGetCardForPinpad(szT2Data, szCardPan);
		if (inRetval == 0) {	//card swipe not success
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = UnAuthCard; //UnAuthCard
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff);
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -1) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY;  //CANCELKEY
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -2) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOSWIPE;  //timeout
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}
		
		for (i=0; i<3; i++) {
			vdScrollDisplay();
			if (i==0) {
				memset(szEncPin, 0x00, sizeof(szEncPin));
				inRetval = inGetPinForPinpad(szEncPin, "ENTER PIN");
			} else if (i==1){
				memset(szEncNewPin1, 0x00, sizeof(szEncNewPin1));
				inRetval = inGetPinForPinpad(szEncNewPin1, "ENTER NEW PIN");
			} else {
				memset(szEncNewPin2, 0x00, sizeof(szEncNewPin2));
				inRetval = inGetPinForPinpad(szEncNewPin2, "RE-ENTER NEW PIN");
			}
			if (inRetval == PP_TIMEOUT) {
				szRespBuff[0] = PINSEND;
				szRespBuff[1] = TOPIN; // ==>timeout
				inRespBuff = 2;
				inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
				vdDisplayPinpadStatus(szRespBuff); 
				SVC_WAIT(5000);
				return 0;
			} else if (inRetval != PP_SUCCESS) {
				szRespBuff[0] = PINSEND;
				szRespBuff[1] = CANCELKEY; //Cancelled
				inRespBuff = 2;
				inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
				vdDisplayPinpadStatus(szRespBuff); 
				SVC_WAIT(5000);
				return 0;
			}
		}
		if (memcmp(szEncNewPin1, szEncNewPin2, 8)) {
			szRespBuff[0] = PINACK;
			inRespBuff = 1;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
			szRespBuff[0] = PINCHANGEREQ;
			szRespBuff[1] = CANCELKEY; //PIN tidak sama
			vdDisplayPinpadStatus(szRespBuff);	
			SVC_WAIT(3000);
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY; //Cancelled
			vdDisplayPinpadStatus(szRespBuff);	
			SVC_WAIT(3000);
			return 0;
		}
		// Send 08h + Track2 Data + 8-byte encrypted OLD PIN block + 8 byte encrypted NEW PIN block
		vdScrollDisplay();
		DisplayStatus("PLEASE WAIT...");
		memset(buff, 0x00, sizeof(buff));
		SVC_DSP_2_HEX(szEncPin, buff, 8);
		szRespBuff[0] = PINCHANGESEND;
		szRespBuff[1] = 0x3B;
		strcpy(&szRespBuff[2], szT2Data);
		memcpy(&szRespBuff[2+strlen(szT2Data)], buff, 8);
		memset(buff, 0x00, sizeof(buff));
		SVC_DSP_2_HEX(szEncNewPin1, buff, 8);
		memcpy(&szRespBuff[2+strlen(szT2Data)+8], buff, 8);
		inRespBuff = 2+strlen(szT2Data)+8+8;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		memset(szReqBuff, 0x00, sizeof(szReqBuff));
		memset(szRespBuff, 0x00, sizeof(szRespBuff));
		inReqBuff = inReadComPort(szReqBuff, 30);
		DisplayStatus(" ");
		if (inReqBuff<=0 || szReqBuff[0] != PINCHANGERES) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOCOMM; // ==>timeout
			inRespBuff = 2;
			vdDisplayPinpadStatus(szRespBuff); 
			DisplayStatus("SYSTEM ERROR");		//or timeout/com error
			SVC_WAIT(5000);
			return 0;
		}
		szRespBuff[0] = PINACK;
		inRespBuff = 1;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
		vdDisplayPinpadStatus(szReqBuff);	//display sesuai response
		SVC_WAIT(5000);
		return 1;						
	} else if (szReqBuff[0] == PINREQ) {
		char szEncPin[20];
		char szCardPan[20];
		char szT2Data[TRACK2_SIZE +1];
		memset(szEncPin, 0x00, sizeof(szEncPin));
		memset(szT2Data, 0x00, sizeof(szT2Data));
		memset(szCardPan, 0x00, sizeof(szCardPan));
		clrscrplus("VERIFIKASI PIN");

		inRetval = inGetCardForPinpad(szT2Data, szCardPan);
		if (inRetval == 0) {	//card swipe not success
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = UnAuthCard; //UnAuthCard
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff);
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -1) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY;  //CANCELKEY
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -2) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOSWIPE;  //timeout
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}

		inRetval = inCheckCardForPinpad(szCardPan, szReqBuff);
		if (inRetval != 1) {	//unauth card swiped
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = UnAuthCard;
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}

		vdScrollDisplay();
		inRetval = inGetPinForPinpad(szEncPin, "ENTER PIN");
		if (inRetval == PP_TIMEOUT) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOPIN; // ==>timeout
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval != PP_SUCCESS) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY; //Cancelled
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}

		// Send 08h + Track2 Data + 8-byte encrypted PIN block
		vdScrollDisplay();
		DisplayStatus("PLEASE WAIT...");
		memset(buff, 0x00, sizeof(buff));
		SVC_DSP_2_HEX(szEncPin, buff, 8);
		szRespBuff[0] = PINSEND;
		szRespBuff[1] = 0x3B;
		strcpy(&szRespBuff[2], szT2Data);
		memcpy(&szRespBuff[2+strlen(szT2Data)], buff, 8);
		inRespBuff = 2+strlen(szT2Data)+8;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		memset(szReqBuff, 0x00, sizeof(szReqBuff));
		memset(szRespBuff, 0x00, sizeof(szRespBuff));
		inReqBuff = inReadComPort(szReqBuff, 30);
		DisplayStatus(" ");
		if (inReqBuff<=0 || szReqBuff[0] != PINRES) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOCOMM; // ==>timeout
			inRespBuff = 2;
			vdDisplayPinpadStatus(szRespBuff); 
			DisplayStatus("SYSTEM ERROR");		//or timeout/com error
			SVC_WAIT(5000);
			return 0;
		}
		szRespBuff[0] = PINACK;
		inRespBuff = 1;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
		vdDisplayPinpadStatus(szReqBuff);	//display sesuai response
		SVC_WAIT(5000);
		return 1;
	} else if (szReqBuff[0] == TINCHANGEREQ) {
		char szEncPin[20];
		char szEncNewTin1[20];
		char szEncNewTin2[20];
		char szCardPan[20];
		char szT2Data[TRACK2_SIZE +1];
		int i=0;
		memset(szT2Data, 0x00, sizeof(szT2Data));
		memset(szCardPan, 0x00, sizeof(szCardPan));
		clrscrplus("CREATE/CHANGE TIN");

		inRetval = inGetCardForPinpad(szT2Data, szCardPan);
		if (inRetval == 0) {	//card swipe not success
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = UnAuthCard; //UnAuthCard
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff);
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -1) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY;  //CANCELKEY
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -2) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOSWIPE;  //timeout
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}
		
		for (i=0; i<3; i++) {
			vdScrollDisplay();
			if (i==0) {
				memset(szEncPin, 0x00, sizeof(szEncPin));
				inRetval = inGetPinForPinpad(szEncPin, "ENTER PIN");
			} else if (i==1){
				memset(szEncNewTin1, 0x00, sizeof(szEncNewTin1));
				inRetval = inGetPinForPinpad(szEncNewTin1, "ENTER NEW TIN");
			} else {
				memset(szEncNewTin2, 0x00, sizeof(szEncNewTin2));
				inRetval = inGetPinForPinpad(szEncNewTin2, "RE-ENTER NEW TIN");
			}
			if (inRetval == PP_TIMEOUT) {
				szRespBuff[0] = PINSEND;
				szRespBuff[1] = TOPIN; // ==>timeout
				inRespBuff = 2;
				inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
				vdDisplayPinpadStatus(szRespBuff); 
				SVC_WAIT(5000);
				return 0;
			} else if (inRetval != PP_SUCCESS) {
				szRespBuff[0] = PINSEND;
				szRespBuff[1] = CANCELKEY; //Cancelled
				inRespBuff = 2;
				inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
				vdDisplayPinpadStatus(szRespBuff); 
				SVC_WAIT(5000);
				return 0;
			}
		}
		if (memcmp(szEncNewTin1, szEncNewTin2, 8)) {
			szRespBuff[0] = PINACK;
			inRespBuff = 1;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
			szRespBuff[0] = TINCHANGEREQ;
			szRespBuff[1] = CANCELKEY; //TIN tidak sama
			vdDisplayPinpadStatus(szRespBuff);	
			SVC_WAIT(3000);
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY; //Cancelled
			vdDisplayPinpadStatus(szRespBuff);	
			SVC_WAIT(3000);
			return 0;
		}
		// Send 08h + Track2 Data + 8-byte encrypted PIN block + 8-byte encryoted TIN block
		vdScrollDisplay();
		DisplayStatus("PLEASE WAIT...");
		memset(buff, 0x00, sizeof(buff));
		SVC_DSP_2_HEX(szEncPin, buff, 8);
		szRespBuff[0] = TINCHANGESEND;
		szRespBuff[1] = 0x3B;
		strcpy(&szRespBuff[2], szT2Data);
		memcpy(&szRespBuff[2+strlen(szT2Data)], buff, 8);
		memset(buff, 0x00, sizeof(buff));
		SVC_DSP_2_HEX(szEncNewTin1, buff, 8);
		memcpy(&szRespBuff[2+strlen(szT2Data)+8], buff, 8);
		inRespBuff = 2+strlen(szT2Data)+8+8;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		memset(szReqBuff, 0x00, sizeof(szReqBuff));
		memset(szRespBuff, 0x00, sizeof(szRespBuff));
		inReqBuff = inReadComPort(szReqBuff, 30);
		DisplayStatus(" ");
		if (inReqBuff<=0 || szReqBuff[0] != TINCHANGERES) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOCOMM; // ==>timeout
			inRespBuff = 2;
			vdDisplayPinpadStatus(szRespBuff); 
			DisplayStatus("SYSTEM ERROR");		//or timeout/com error
			SVC_WAIT(5000);
			return 0;
		}
		szRespBuff[0] = PINACK;
		inRespBuff = 1;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
		vdDisplayPinpadStatus(szReqBuff);	//display sesuai response
		SVC_WAIT(5000);
		return 1;						
	} else if (szReqBuff[0] == TINREQ) {
		char szEncTin[20];
		char szCardPan[20];
		memset(szEncTin, 0x00, sizeof(szEncTin));
		memset(szCardPan, 0x00, sizeof(szCardPan));
		clrscrplus("VERIFIKASI TIN");

		szReqBuff[17] = 0x00;
		strncpy(szCardPan, &szReqBuff[1], 16);
		vdTrimSpace(szCardPan);
		if (strlen(szCardPan)==0) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = UnAuthCard;
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}

		vdScrollDisplay();
		inRetval = inGetPinForPinpad(szEncTin, "ENTER TIN");
		if (inRetval == PP_TIMEOUT) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOPIN; // ==>timeout
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval != PP_SUCCESS) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY; //Cancelled
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}

		// Send 08h + PAN Data + 8-byte encrypted TIN block
		vdScrollDisplay();
		DisplayStatus("PLEASE WAIT...");
		memset(buff, 0x00, sizeof(buff));
		SVC_DSP_2_HEX(szEncTin, buff, 8);
		szRespBuff[0] = PINSEND;
		strcpy(&szRespBuff[1], szCardPan);
		memcpy(&szRespBuff[1+strlen(szCardPan)], buff, 8);
		inRespBuff = 1+strlen(szCardPan)+8;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		memset(szReqBuff, 0x00, sizeof(szReqBuff));
		memset(szRespBuff, 0x00, sizeof(szRespBuff));
		inReqBuff = inReadComPort(szReqBuff, 30);
		DisplayStatus(" ");
		if (inReqBuff<=0 || szReqBuff[0] != PINRES) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOCOMM; // ==>timeout
			inRespBuff = 2;
			vdDisplayPinpadStatus(szRespBuff); 
			DisplayStatus("SYSTEM ERROR");		//or timeout/com error
			SVC_WAIT(5000);
			return 0;
		}
		szRespBuff[0] = PINACK;
		inRespBuff = 1;
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);	
		vdDisplayPinpadStatus(szReqBuff);	//display sesuai response
		SVC_WAIT(5000);
		return 1;
	} else if (szReqBuff[0] == CARDCAPREQ) {
		char szCardPan[20];
		char szT2Data[TRACK2_SIZE +1];
		memset(szT2Data, 0x00, sizeof(szT2Data));
		memset(szCardPan, 0x00, sizeof(szCardPan));
		clrscrplus("CARD CAPTURE");

		inRetval = inGetCardForPinpad(szT2Data, szCardPan);
		if (inRetval == 0) {	//card swipe not success
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = UnAuthCard; //UnAuthCard
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff);
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -1) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = CANCELKEY;  //CANCELKEY
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		} else if (inRetval == -2) {
			szRespBuff[0] = PINSEND;
			szRespBuff[1] = TOSWIPE;  //timeout
			inRespBuff = 2;
			inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
			vdDisplayPinpadStatus(szRespBuff); 
			SVC_WAIT(5000);
			return 0;
		}
		// Send 08h + Track2 + 8-byte encrypted TIN block
		vdScrollDisplay();
		DisplayStatus("PLEASE WAIT...");
		szRespBuff[0] = CARDCAPSEND;
		szRespBuff[1] = 0x3B;
		strcpy(&szRespBuff[2], szT2Data);
		inRespBuff = 2+strlen(szT2Data);
		inRetval = inWriteComPort(szRespBuff, inRespBuff, 15);
		vdDisplayPinpadStatus(szRespBuff);	
		SVC_WAIT(5000);
		return 1;
	} else {									//unknown PP Req
		DisplayStatus("Unknown PP Req");
		inCloseComPort();
		inInitComPortForPinpad();
		SVC_WAIT(3000);
		return 0;
	}
	return 1;
}

int inInitComPortForPinpad()
{		
	char buff[128];
	open_block_t sOpenBlk;

    if (inEnableFrontEndPinpad()==0) return 0;

	memset((void *)&sOpenBlk, 0x00, sizeof(open_block_t));
	sOpenBlk.trailer.net_parms.retries = 0;
	sOpenBlk.trailer.net_parms.timeout = 30000;
	
	//Define the protocol as: 1200 baud, async, 7 data bits, even parity, and character mode.
	sOpenBlk.rate = Rt_19200;					//Rt_1200; 
	sOpenBlk.format = Fmt_A8N1;					//8 Data bits, none parity and one stop bit (by default) //Fmt_A7E1;
	sOpenBlk.protocol = P_char_mode; 
	//sOpenBlk.parameter = 0x00;

	hComPort = open(DEV_COM1, 0);
	set_opn_blk(hComPort,&sOpenBlk); 

	//read(hComPort, buff, sizeof(buff)-1);  //empty the buffer
	return 1;
}

int inCloseComPort()
{
	if (inEnableFrontEndPinpad()==0) return 0;
	close(hComPort);
	hComPort = 0;
}

int inReadComPort(char *Recv, int inTimeOut)
{
	int inRetval = 0;
	TimeOut(inTimeOut * 1000);
	do {
		if (TimeOut(0)) break;
		SVC_WAIT(100);
		inRetval = read(hComPort, Recv, 128);
	} while (inRetval <= 0);

	if (inRetval <= 0) {
		DisplayStatus("Read Com TimeOut!");
		inCloseComPort();
		inInitComPortForPinpad();
		SVC_WAIT(2000);
		return 0;
	}
	return inRetval;
}

int inWriteComPort(char *Sent, int inSentSize, int inTimeOut)
{
	int inRetval = 0;
	
	inRetval = write(hComPort, Sent, inSentSize);

	if (inRetval <= 0) {
		DisplayStatus("Write Com Failed!");
		inCloseComPort();
		inInitComPortForPinpad();
		SVC_WAIT(2000);
		return 0;
	}	
	return inRetval;
}

int inSelectPinpadMasterKey()
{
    char pchPINBuf[PINPAD_BUFFER_SIZE];

    memset(pchPINBuf, 0x00, sizeof(pchPINBuf));
    pchPINBuf[0] = SI;
    strcat(pchPINBuf, "08");
    //pchPINBuf[strlen(pchPINBuf)] = chGetMasterKeyAddress();
	pchPINBuf[strlen(pchPINBuf)] = '1';
    pchPINBuf[strlen(pchPINBuf)] = SO;

    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS)
        return(VS_ERR);
    else
        return(VS_SUCCESS);
}

int inGetPinForPinpad(char *szEPin, char *label) 
{
    char szPAN[PAN_SIZE + 1], szPINBlock[PIN_SIZE + 1];
    char szMaxPIN[2 + 1], szMinPIN[2 + 1];
    char pchPINBuf[PINPAD_BUFFER_SIZE];
    char szKSN[KSN_SIZE+1];
    int  inSize, inCnt=0;                      /* No of retries set to 0 */
    char pszEncKey[PIN_SIZE + 1];
	char buff[128];

    vdFlushKeyboardBuffer();
    memset(szKSN, '\0', sizeof(szKSN));

    if (inPPadConnectTest() != VS_SUCCESS) {
       DisplayStatus("PP ERR: Not Connect");
       return(PP_ERROR);
    }
    if (inSelectPinpadMasterKey() != VS_SUCCESS) {
		DisplayStatus("PP ERR: MKey Fail");
		return(PP_ERROR);
	}
	if (strlen(szWorkingKey) != 16) {
		DisplayStatus("INVALID WORKING KEY");
		return (PP_ERROR);
	}
	memset(pszEncKey, 0x00, sizeof(pszEncKey));
	strcpy(pszEncKey, szWorkingKey);
	strcpy(szPAN,	   "0000000000000000");
    sprintf(szMinPIN, "%02d", 4);
    sprintf(szMaxPIN, "%02d", 6); 

    memset(pchPINBuf, 0, sizeof(pchPINBuf));
    strcpy(pchPINBuf, "Z63.");              /* Start of packet */
    strcat(pchPINBuf, szPAN);               /* Card Account Number */
    pchPINBuf[strlen(pchPINBuf)] = FS;      /* To separate the Account Number */
    strcat(pchPINBuf, pszEncKey);			/* Append Working Key for Master-Session */
    strcat(pchPINBuf, szMinPIN);            /* Minimum PIN length */
    strcat(pchPINBuf, szMaxPIN);            /* Maximum PIN length */
    pchPINBuf[strlen(pchPINBuf)] = 'N';     /* Null PIN allowed flag; 'N' = No null PIN */
    pchPINBuf[strlen(pchPINBuf)] = '*';     /* Echo char */
    
    vdFlushKeyboardBuffer();
    vdWarnBeep();
	write_at(label, strlen(label), 1, 7);
	if (strlen(label)>=15) vdScrollDisplay();
    gotoxy(15, 7);  // Set up so PIN entry will start here
	set_font("");  // This is needed for the backspace to work, by using the default font.
	
    if (inSendPinPadData(pchPINBuf, inGetPPTimeOut(), VS_TRUE) != VS_SUCCESS){
		LOG_PRINTFF((0x08L, "Error inSendPinPadData"));
		DisplayStatus("PP ERR: Cannot Send");
        return(PP_ERROR);       /* Exit if inSendPinPadData fails */
	}        
    inSize = inRecvPinPadData(pchPINBuf, inGetPPTimeOut(), sizeof(pchPINBuf), VS_TRUE);
    if (inSize == VS_ESCAPE) {   /* Aborting from terminal, via Clear key */
		LOG_PRINTFF((0x08L, "PIN Entry Cancel"));
		DisplayStatus("PIN ENTRY CANCEL");
        return(PP_CANCEL);
	}
    if ((inSize == 0) || (inSize == VS_TIMEOUT)) {
		LOG_PRINTFF((0x08L, "PINPad Timeout Error, size = 0"));
		DisplayStatus("PP TIME OUT");
        if (inResetPINPad() != VS_SUCCESS)
            return(PP_ERROR);
        return(PP_TIMEOUT);             /* Nothing Received */
    }
    if (inGetEncryptMethod() != DUKPT)
        if ((inSize != PINPAD_PIN_RESP_LEN) && (pchPINBuf[0] != EOT)) {
            if (!memcmp(&(pchPINBuf[1]), "71", 2)) {
                vdDispPinPadPkt73Error(pchPINBuf[3]);
				SVC_WAIT(1000);
				LOG_PRINTFF((0x08L, "An Error Occured"));
            }
			LOG_PRINTFF((0x08L, "PINPad Timeout Error"));
			DisplayStatus("PP TIME OUT");
            return(PP_TIMEOUT);
        }
		if (pchPINBuf[0] == EOT) {           /* CANCEL to act as Correction Key */
			LOG_PRINTFF((0x08L, "PIN Entry Cancel as corecction"));
			DisplayStatus("PIN ENTRY CANCEL");
			return(PP_CANCEL);
		}
    if (inGetEncryptMethod() != DUKPT){
        strlcpy(szPINBlock, &(pchPINBuf[9]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */
    } else {
        if ((!memcmp(&(pchPINBuf[1]), "73", 2)) && inSize == 6) {
            vdDispPinPadPkt73Error(pchPINBuf[3]);
        }            
        /* The expected packet is <STX>710[KSN 16-20][PIN Block 16]<ETX> */
        while (pchPINBuf[inCnt] != ETX && inCnt < (int)strlen(pchPINBuf))
            inCnt++;
        strlcpy(szPINBlock, &(pchPINBuf[inCnt-PIN_BLOCK_SIZE]), PIN_BLOCK_SIZE); /* Copy PIN block to Appl Buff */
        strlcpy(szKSN, &(pchPINBuf[9]), inCnt-9-PIN_BLOCK_SIZE);
        pad(szKSN, szKSN, 'F', KSN_SIZE - 9, RIGHT);
        //strlcpy(pobTran->szKSN, szKSN, KSN_SIZE);
    }
    if (szPINBlock[0] == '\0') {
		LOG_PRINTFF((0x08L, "PINPad Buffer Empty Error"));
		DisplayStatus("PP INTERNAL ERROR");
        return (PP_CANCEL);
	}
    if (inResetPINPad() != VS_SUCCESS) {     /* Return PinPad to Idle */
		LOG_PRINTFF((0x08L, "PP ERR: RESET FAIL"));
        return(PP_ERROR);
	}
    strlcpy(szEPin, szPINBlock, PIN_SIZE);  /* Set in the Transaction Object */
	LOG_PRINTFF((0x08L, "%s", szPINBlock));
	LOG_PRINTFF((0x08L, "%s", szKSN));
    LOG_PRINTFF((0x08L, "PIN Entry Success"));
	vdFlushKeyboardBuffer();
    return(PP_SUCCESS);    
}

extern short hMagReader;
int inGetCardForPinpad(char *szTrack2, char *szPAN)
{
    int i;
	short	shRetVal = 0 ;
    char	szRawCardData[CARD_SIZE] ;
	int     kar;
	struct	TRACK stParsedCardData ;	// Card Data Holder
	char	szCardHolderName[CHOLDER_SIZE + 1];
	char	buff[22];

	//write_at("Enter Card Number or", 20, 1, 4);  //display logo swipe here if needed
	//write_at(" Swipe Customer Card", 20, 1, 5);
	vdDisplayPinpadStatus("\xFF\xFF");  //display gesek kartu anda
	TimeOut(15000);
	do {
		if (card_pending()==1) {
			break;
		}
		if (KBHIT()){
			if (get_char()==27) {
				DisplayStatus("SWIPE CANCEL");
				return -1;
			}
		}
		if (TimeOut(0)) {
			DisplayStatus("SWIPE TIME OUT!");
			return -2;
		}
		SVC_WAIT(0);
	}while (1);

	shRetVal = read(hMagReader, szRawCardData, sizeof(szRawCardData)) ;
    if(shRetVal < 0)
	{
		DisplayStatus("Can't read Card Data");
		vdWarnBeep();
        return 0 ;
	}
	//parse the card data
	memset((void *)&stParsedCardData, 0x00, sizeof(stParsedCardData));
	memset(szCardHolderName, 0x00, sizeof(szCardHolderName));
	shRetVal = card_parse(szRawCardData, &stParsedCardData, "1") ;
	if (shRetVal == 1) {
		strcpy(szCardHolderName, stParsedCardData.name);
		vdTrimSpace(szCardHolderName);
	}
    shRetVal = card_parse(szRawCardData, &stParsedCardData, "2") ;
	if (shRetVal == 2) {
		strcpy(szTrack2, stParsedCardData.track);
		strcpy(szPAN, stParsedCardData.acct);
    } else {
		DisplayStatus("Error in Card Parsing");
		vdWarnBeep();
        return 0 ;
	}
	LOG_PRINTFF((0x08L, "Parsed Track2 (%d) = %s", strlen(stParsedCardData.track), stParsedCardData.track));
	for (i=0; i<7; i++) vdScrollDisplay();

/*
	if (strlen(szCardHolderName)) {
		vdScrollDisplay();
		szCardHolderName[16] = 0x00;
		display_at(1, 7, "NAMA", CLR_EOL);
		display_at(22-strlen(szCardHolderName), 7, szCardHolderName, CLR_EOL);	
	}
*/
	vdScrollDisplay();
	display_at(1, 7, "PAN", CLR_EOL);
	display_at(22-strlen(stParsedCardData.acct), 7, stParsedCardData.acct, CLR_EOL);
	vdScrollDisplay();
	memset(buff, 0x00, sizeof(buff));
	strncat(buff, &stParsedCardData.exp[2], 2);
	strncat(buff, &stParsedCardData.exp[0], 2);
	display_at(1, 7, "EXP.(MMYY)", CLR_EOL);
	display_at(22-strlen(buff), 7, buff, CLR_EOL);
	return 1;
	//return inCheckCard(pobTran);
}

int inCheckCardForPinpad(char *szPAN, char *szReqBuff)
{
	if (strncmp(szPAN, &szReqBuff[1], 16)==0 || 
		strncmp(szPAN, &szReqBuff[17], 16)==0 || 
		strncmp(szPAN, &szReqBuff[33], 16)==0) {
		return 1;
	}
	DisplayStatus("UNAUTH CARD");
	return 0;
}

void vdDisplayPinpadStatus(char *szCode)
{
	int i;
	char buff[30];
	char szFont[30];
	char szBmpFont[30];
	char inPosFont=0;
	memset(szFont, 0x00, sizeof(szFont));
	memset(szBmpFont, 0x00, sizeof(szBmpFont));
	memset(buff, 0x00, sizeof(buff));



	if (((unsigned char)szCode[0]==0xFF) && ((unsigned char)szCode[1]==0xFF)) {
		strcpy(szBmpFont, "F:PPBMP4.VFT");
		inPosFont=8;
	} else if ((szCode[0]==PINSEND) && (szCode[1]==UnAuthCard)) {       //card unauth
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 1;
	} else if ((szCode[0]==PINSEND) && (szCode[1]==TOSWIPE)) {	  //Swipe timeout
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 2;
	} else if ((szCode[0]==PINSEND) && (szCode[1]==CANCELKEY)) { //Trx cancelled
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 3;
	} else if ((szCode[0]==PINSEND) && (szCode[1]==TOPIN)) {     //pin/tin entry timeout
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 4;
	} else if ((szCode[0]==PINCREATEREQ) && (szCode[1]==CANCELKEY)) { //pin baru tidak sama
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 5;
	} else if ((szCode[0]==PINCHANGEREQ) && (szCode[1]==CANCELKEY)) { //idem
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 5;
	} else if ((szCode[0]==TINCHANGEREQ) && (szCode[1]==CANCELKEY)) { //tin baru tidak sama
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 6;
	} else if ((szCode[0]==PINSEND) && (szCode[1]==TOCOMM)) {	  //general communication error
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 7;
	} else if (szCode[0]==CARDCAPSEND) {						//terima kasih
		strcpy(szBmpFont, "F:PPBMP1.VFT");
		inPosFont = 8;
	} else if (szCode[0]==PINRES || szCode[0]==PINCREATERES || szCode[0]==PINCHANGERES || szCode[0]==TINCHANGERES) {
		if (szCode[1]==0x00 || szCode[1]==0x08 || szCode[1]==0x10 || szCode[1]==0x11 || szCode[1]==0x16) { 
			if (chCommandSession==PINREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 1;
			} else if (chCommandSession==PINCREATEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 2;
			} else if (chCommandSession==PINCHANGEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 2;
			} else if (chCommandSession==TINCHANGEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 3;
			} else if (chCommandSession==TINREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 4;
			} else { //terimakasih
				strcpy(szBmpFont, "F:PPBMP1.VFT");
				inPosFont = 8;
			}
		} else if (szCode[1]==0x55) { 
			if (chCommandSession==PINREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 5;
			} else if (chCommandSession==PINCREATEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 5;
			} else if (chCommandSession==PINCHANGEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 5;
			} else if (chCommandSession==TINCHANGEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 5;
			} else if (chCommandSession==TINREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 6;
			} 
		} else if (szCode[1]==0x38 || szCode[1]==0x75) { 
			if (chCommandSession==PINREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 7;
			} else if (chCommandSession==PINCREATEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 7;
			} else if (chCommandSession==PINCHANGEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 7;
			} else if (chCommandSession==TINCHANGEREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 7;
			} else if (chCommandSession==TINREQ) {
				strcpy(szBmpFont, "F:PPBMP2.VFT");
				inPosFont = 8;
			} 
		} else if (szCode[1]==0x04 || szCode[1]==0x07 || szCode[1]==0x34 ||
				   szCode[1]==0x35 || szCode[1]==0x36 || szCode[1]==0x37 || 
				   szCode[1]==0x41 || szCode[1]==0x43 || szCode[1]==0x67) { //status kartu terblokir
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 1;
		} else if (szCode[1]==0x14) {										//kartu tidak dikenal
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 2;
		} else if (szCode[1]==0x33 || szCode[1]==0x54) {					//kartu tidak berlaku
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 3;
		} else if (szCode[1]==0x59) {										//kartu tidak dapat diproses
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 4;
		} else if (szCode[1]==0x62) {										//kartu kartu terblokir/tutup
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 5;
		} else if (szCode[1]==0x68 || (unsigned char)szCode[1]==0x91) {					//kamonukasi terganggu
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 6;
		} else if ((unsigned char)szCode[1]==0xA0) {										//Anda belum buat tin
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 7;
		} else if ((unsigned char)szCode[1]==0xA1) {										//Tin anda terblokir
			strcpy(szBmpFont, "F:PPBMP3.VFT");
			inPosFont = 8;
		} else if ((unsigned char)szCode[1]==0x84)	{										//system error
			strcpy(szBmpFont, "F:PPBMP4.VFT");
			inPosFont = 1;
		} else {  //transaksi gagal
			strcpy(szBmpFont, "F:PPBMP4.VFT");
			inPosFont = 2;
			//posisi dari szCode==0x01 ==> 0xFF
			//sprintf(szBmpFont, "F:PP_R%d.VFT", ((int)szCode[1]-1)/8); 
			//inPosFont = ((int)szCode[1]-1)%8 + 1;
		} 
	}
	for (i=0; i<16; i++) {
		buff[i] = ((inPosFont-1)*16)+i;
	}
	get_font(szFont);
	set_font("");
	for (i=2; i<8; i++) write_at("                      ", 21, 1, i);
	set_font(szBmpFont);		
	write_at(buff, 16, 1, 2);
	set_font(szFont);
}